package org.kernely.core;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.kernely.core.service.BundlePresentService;
import org.kernely.core.service.KernelyBundleService;
import org.kernely.core.service.KernelySettingsService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceReference;


public class Activator implements BundleActivator, BundleListener {
	
	private BundleContext context;
	
	/**
	 * This method is called when the bundle's state pass to STARTED
	 */
    public final void start(BundleContext context) throws Exception {
    	this.context = context;
    	// Register this bundle as a BundleListener
        context.addBundleListener(this);
        Properties props = new Properties();
        props.put("Language", "English");
        // Services registration
        context.registerService(BundlePresentService.class.getName(), new BundleCheckImpl(), props);
        context.registerService(KernelyBundleService.class.getName(), new KernelyBundleServiceImpl(), props);
        context.registerService(KernelySettingsService.class.getName(), new KernelySettingsServiceImpl(), props);
        
        // Retrieve Apache Preferences service
		// ServiceReference ref =
		// context.getServiceReference(PreferencesService.class.getName());
		// if (ref != null)
		// {
		// PreferencesService service = (PreferencesService)
		// context.getService(ref);
		// KernelySettingsServiceImpl.setPreferencesService(service);
		// }
		// Retrieve Apache Log service
		// ServiceReference ref2 =
		// context.getServiceReference(LogService.class.getName());
		// if (ref2 != null)
		// {
		// LogService log = (LogService) context.getService(ref2);
		// log.log(LogService.LOG_INFO, "Starting bundle listening...");
		// KernelyBundleServiceImpl.setLogger(log);
		// }
    }

    /**
     * This method is called when the bundle's state is STOPPING
     */
    public final void stop(BundleContext context) throws Exception {
        context.removeBundleListener(this);
    }
	
    /**
     * Method called when the bundle's state change
     */
    public final void bundleChanged(BundleEvent event) {
		// Retrieve the event
		Bundle bundle = event.getBundle();
		try{
			ServiceReference[] refs = context.getServiceReferences(BundlePresentService.class.getName(), "(Language=*)");
			BundlePresentService bundleChecker = (BundlePresentService) context.getService(refs[0]);
			if (event.getType()==BundleEvent.STARTED){
				if(refs != null){
					// Mark the bundle as analysed
					bundleChecker.addRegisteredBundle(bundle);
				}
			}
			if (event.getType()==BundleEvent.UNINSTALLED){
				if(refs != null){
					// Remove the bundle from analysed bundles list
					bundleChecker.removeRegisteredBundle(bundle);
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	
	
	/**
	 * Implementation class for the service BundlePresentService 
	 */
	private static class BundleCheckImpl implements BundlePresentService
    {
		private Map<String, HashMap<String, String>> bundles = new HashMap<String, HashMap<String, String>>();
		
		/**
		 * Implements the BundlePresentService Service : return true if the bundle is already present, false else.
		 */
		public final boolean checkBundle(Bundle bundle) {
      		if(bundles.containsKey(bundle.getSymbolicName())){
				// Compare on the bundle's symbolic name
				return true;
			}
			return false;
		}
      	
      	/**
      	 * Allows to add a bundle at the list, refresh the actual context
      	 */
		public final void addRegisteredBundle(Bundle bundle){
      		HashMap<String, String> hm = new HashMap<String, String>();
      		hm.put("version", bundle.getVersion().toString());
      		this.bundles.put(bundle.getSymbolicName(), hm);
      	}
      	
      	/**
      	 * Remove the bundle from the list
      	 */
		public final void removeRegisteredBundle(Bundle bundle){
      		this.bundles.remove(bundle.getSymbolicName());
      	}
      	
      	/**
      	 * Return the version of given bundle.
      	 */
		public final String getBundleVersion(Bundle bundle){
      		return this.bundles.get(bundle.getSymbolicName()).get("version");
      	}
    }

}
